Conversation
WalkthroughPR는 마이페이지의 프로필 관리 시스템을 재구성합니다. 새로운 모달 기반 계정 보안/프로필 편집 UI를 추가하고, 활동/포인트 섹션을 목 데이터에서 실제 API 기반 페이징으로 전환하며, 세션 관리 드롭다운 바인딩을 수정합니다. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant EditProfileModal
participant EmailVerify
participant API
participant Toast
User->>EditProfileModal: 모달 열기
EditProfileModal->>EditProfileModal: 메뉴 표시
User->>EditProfileModal: "이메일 변경하기" 선택
EditProfileModal->>EmailVerify: 이메일 인증 스텝으로 전환
User->>EmailVerify: 이메일 입력
User->>EmailVerify: "인증번호 전송" 버튼 클릭
EmailVerify->>API: POST /api/user/email/verification 호출
API-->>EmailVerify: 인증번호 전송 완료
EmailVerify->>Toast: 성공 메시지 표시
EmailVerify->>EmailVerify: 카운트다운 타이머 시작 (180초)
User->>EmailVerify: 인증번호 입력
User->>EmailVerify: "인증하기" 버튼 클릭
EmailVerify->>API: POST /api/user/email/verify 호출
API-->>EmailVerify: 인증 성공
EmailVerify->>EditProfileModal: onVerified(email) 콜백
EditProfileModal->>EditProfileModal: 최종 제출 스텝으로 이동
User->>EditProfileModal: "확인" 버튼 클릭
EditProfileModal->>API: PATCH /api/user/details { email }
API-->>EditProfileModal: 업데이트 완료
EditProfileModal->>Toast: 성공 메시지 표시
EditProfileModal->>User: 모달 닫기
sequenceDiagram
participant User
participant EditProfileModal
participant ChangeInfoForm
participant API
participant Toast
User->>EditProfileModal: 모달 열기
EditProfileModal->>EditProfileModal: 메뉴 표시
User->>EditProfileModal: "비밀번호 변경하기" 선택
EditProfileModal->>EditProfileModal: 인증 스텝으로 전환
EditProfileModal->>ChangeInfoForm: 비밀번호 입력 폼 (현재 비밀번호 필드만)
User->>ChangeInfoForm: 현재 비밀번호 입력
EditProfileModal->>EditProfileModal: 형식 스텝으로 이동
EditProfileModal->>ChangeInfoForm: 새 비밀번호/확인 폼으로 전환
ChangeInfoForm->>ChangeInfoForm: 비밀번호 정책 검증 (길이, 대문자, 소문자, 숫자, 특수문자)
User->>ChangeInfoForm: 새 비밀번호 입력
ChangeInfoForm->>ChangeInfoForm: 유효성 확인
ChangeInfoForm->>EditProfileModal: onValidChange({ currentPassword, newPassword })
User->>EditProfileModal: "확인" 버튼 클릭
EditProfileModal->>API: PATCH /api/user/details { currentPassword, newPassword }
API-->>EditProfileModal: 업데이트 완료
EditProfileModal->>Toast: 성공 메시지 표시
EditProfileModal->>User: 모달 닫기
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 12
🧹 Nitpick comments (1)
frontend/src/components/attendancemanage/SessionManagementCard.jsx (1)
4-7: 선택 사항: 사용되지 않는 import 정리코드 정리를 위해
useContext(Line 4)와addRound(Line 7)가 이 파일에서 더 이상 사용되지 않으므로 제거를 고려해 보세요. 또한handleAddRounds(Line 23)도 이 컴포넌트에서는 사용되지 않고RoundDayPicker에서만 사용됩니다.♻️ 제안된 수정
-import { useContext, useEffect, useState } from 'react'; +import { useEffect, useState } from 'react'; import { toast } from 'react-toastify'; import { useAttendance } from '../../contexts/AttendanceContext'; -import { getRounds, addRound } from '../../utils/attendanceManage'; +import { getRounds } from '../../utils/attendanceManage';그리고 useAttendance에서
handleAddRounds제거:const { sessions, roundsVersion, - handleAddRounds, openAddRoundsModal, selectedSessionId, setSelectedSessionId, } = useAttendance();🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/src/components/attendancemanage/SessionManagementCard.jsx` around lines 4 - 7, Remove unused imports and props: delete the unused useContext import and the addRound import from SessionManagementCard.jsx and remove the unused handleAddRounds prop usage from this component (handleAddRounds is only used inside RoundDayPicker). Update any destructuring from useAttendance to stop expecting handleAddRounds so the context hook usage matches actual consumers (e.g., adjust the useAttendance() destructure in SessionManagementCard to exclude handleAddRounds). Ensure RoundDayPicker continues to receive and use handleAddRounds from useAttendance where needed.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@frontend/src/components/mypage/ActivitySection.jsx`:
- Around line 11-27: fetchActivityLogs currently leaves the UI ambiguous during
network delays because it only updates items and totalPages; add explicit
loading and error state handling: introduce local state variables (e.g.,
loading, setLoading and error, setError) in ActivitySection.jsx,
setLoading(true) before awaiting getActivityLogs(page, size), clear error on
start, set items and totalPages on success, setError(error) in the catch block,
and setLoading(false) in a finally block; also update the component render
(including the JSX referenced around the fetch usage lines ~51-65) to show a
loading indicator when loading is true, an error message when error is set, and
only show the "no items" / list UI when not loading and no error.
In `@frontend/src/components/mypage/ChangeInfoForm.jsx`:
- Around line 22-29: The effect in ChangeInfoForm (useEffect) currently only
calls onValidChange when isValid is true, so the parent never sees validation
become false; change the effect to call onValidChange on every validation change
(dependencies: currentPassword, newPassword, confirmPassword) and pass the
validation state and data — e.g., call onValidChange(isValid ? {
currentPassword, newPassword } : null) or pass an object like { valid: isValid,
data: isValid ? { currentPassword, newPassword } : null } so the parent
(EditProfileModal) can clear formValid and passwordData when invalid.
In `@frontend/src/components/mypage/EditProfileModal.jsx`:
- Around line 90-118: Add an isSubmitting state flag and use it to prevent
duplicate requests: at the top of handleSubmit check if isSubmitting and return
early, set isSubmitting = true before any await/updateUserDetails call, and
ensure you set isSubmitting = false in a finally block so it always resets; also
disable the primary button (e.g., disabled={isSubmitting} or show a loading
state) so the UI cannot trigger parallel submits during the mode/step flows
(references: handleSubmit, updateUserDetails, mode, step); apply the same
isSubmitting guard and UI disable to the other submit handler(s) in this
component that perform PATCH requests (the second submit path handling
email/password flows).
- Around line 124-129: The modal lacks ARIA dialog semantics; update the modal
container (the element with className styles.modal) to include role="dialog" and
aria-modal="true", add an id to the header element that renders getHeaderTitle()
(e.g., "edit-profile-modal-title") and connect it via aria-labelledby on the
dialog, and ensure the header <h1> uses that id so screen readers recognize the
title; make these changes inside the EditProfileModal component (look for
styles.overlay, styles.modal, and the getHeaderTitle() usage).
In `@frontend/src/components/mypage/EditProfileModal.module.css`:
- Around line 1-27: The overlay and modal lack vertical scroll control causing
the modal bottom to be inaccessible on small viewports; update the .overlay to
allow scrolling (e.g., overflow-y: auto; -webkit-overflow-scrolling: touch) and
set .modal to a max-height based on the viewport (e.g., max-height: calc(100vh -
40px)) with overflow-y: auto so its internal content can scroll while keeping
the modal centered and paddings intact; apply these changes to the .overlay and
.modal rules to ensure the bottom buttons remain reachable on
mobile/virtual-keyboard scenarios.
In `@frontend/src/components/mypage/EmailVerify.jsx`:
- Around line 19-20: The AbortController created in the EmailVerify component
isn't wired to the actual request: set abortRef.current to the new controller
(and call abortRef.current.abort() if an existing controller exists) before
making the network call, and pass controller.signal into the fetch/axios request
so the previous request can be cancelled; update the code around the controller
creation (where controller is instantiated) and the request invocation (where
signal should be supplied) to use abortRef and controller.signal accordingly.
- Around line 46-58: The current "currentEmail" verification allows any email
because handleSend calls sendVerificationNumber({ email }) with only the
user-supplied value; change the flow so the checked email is the authenticated
user's email (not an arbitrary input) or enforce server-side matching: update
the client-side handlers (handleSend and the corresponding verify handler around
lines where sendVerificationNumber and verifyVerificationNumber are called) to
fetch/use the logged-in user's email from the auth state (or disable editing of
the currentEmail input) before calling sendVerificationNumber, and/or update the
API endpoints invoked by sendVerificationNumber/verifyVerificationNumber to
validate that the target email equals the authenticated user's email
(session/token) so an attacker cannot verify a different address; reference
handleSend, sendVerificationNumber, verifyVerificationNumber, and the
EditProfileModal currentEmail step when making the change.
In `@frontend/src/components/mypage/PointsSection.jsx`:
- Line 1: The page fetch logic in PointsSection is vulnerable to out-of-order
responses when users click page buttons rapidly; update the component
(PointsSection) so the effect/handler that calls the data loader (e.g.,
fetchItems or fetchPoints) cancels stale requests or ignores late responses:
either use an AbortController and pass its signal to the fetch call inside
useEffect and abort the previous controller on cleanup, or implement a monotonic
requestId/sequence token checked before calling setItems/setLoading; ensure this
change touches the useEffect that depends on currentPage (and any page change
handler) so only the latest response updates state (items, loading, error) and
previous responses are ignored/aborted.
In `@frontend/src/components/mypage/ProfileCard.jsx`:
- Around line 9-15: The roleMap constant is missing an entry for PENDING_MEMBER
so pending users fall back to the generic label; update the roleMap object
(symbol: roleMap in ProfileCard.jsx) to include a PENDING_MEMBER key with the
appropriate Korean label (e.g., '승인대기' or similar) and ensure any other nearby
mappings (lines around the existing ROLE keys) are consistent with backend
Role.java so pending members display correctly.
- Around line 26-27: The debug console log in ProfileCard.jsx prints the full
/api/user/details response (api.get('/api/user/details')) which exposes PII
(email, phoneNumber); remove the console.log('사용자 정보:', response.data) from the
release code or replace it with a safe log that only outputs non-PII fields
(e.g., username/id) by destructuring response.data to exclude email and
phoneNumber before logging or simply delete the log line in the function that
handles the API response.
In `@frontend/src/utils/axios.js`:
- Around line 2-5: The axios instance is created with baseURL set to an empty
string while BASE_URL is computed, causing API requests and the token refresh
flow (which already uses BASE_URL) to target different hosts in production;
update the axios.create call (the exported api instance) to use baseURL:
BASE_URL so normal API calls and the token-reissue/refresh requests use the same
origin/host, and keep withCredentials: true to preserve credentials across both
flows.
In `@frontend/src/utils/myPageMenu.js`:
- Around line 19-28: getActivityLogs currently returns a raw array but
ActivitySection.jsx expects an object with content and totalPages; update
getActivityLogs to normalize the API response: if response.data is an object
with response.data.content return that as-is, otherwise wrap the array into {
content: response.data, totalPages: 1 } (or compute totalPages from a response
header if backend provides total count) so callers (ActivitySection.jsx) always
receive { content, totalPages } from getActivityLogs.
---
Nitpick comments:
In `@frontend/src/components/attendancemanage/SessionManagementCard.jsx`:
- Around line 4-7: Remove unused imports and props: delete the unused useContext
import and the addRound import from SessionManagementCard.jsx and remove the
unused handleAddRounds prop usage from this component (handleAddRounds is only
used inside RoundDayPicker). Update any destructuring from useAttendance to stop
expecting handleAddRounds so the context hook usage matches actual consumers
(e.g., adjust the useAttendance() destructure in SessionManagementCard to
exclude handleAddRounds). Ensure RoundDayPicker continues to receive and use
handleAddRounds from useAttendance where needed.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 037bda20-b1ec-4ced-95de-7e53e2d0a247
⛔ Files ignored due to path filters (2)
frontend/src/assets/right-arrow.svgis excluded by!**/*.svgfrontend/src/assets/setting_icon.svgis excluded by!**/*.svg
📒 Files selected for processing (19)
frontend/src/components/attendancemanage/SessionManagementCard.jsxfrontend/src/components/mypage/AccountSecurity.jsxfrontend/src/components/mypage/ActivityModal.module.cssfrontend/src/components/mypage/ActivitySection.jsxfrontend/src/components/mypage/ChangeInfoForm.jsxfrontend/src/components/mypage/EditProfileModal.jsxfrontend/src/components/mypage/EditProfileModal.module.cssfrontend/src/components/mypage/EmailVerify.jsxfrontend/src/components/mypage/MyPageMenu.jsxfrontend/src/components/mypage/MyPageMenu.module.cssfrontend/src/components/mypage/PointsSection.jsxfrontend/src/components/mypage/ProfileCard.jsxfrontend/src/components/mypage/ProfileCard.module.cssfrontend/src/pages/Mypage.jsxfrontend/src/pages/Mypage.module.cssfrontend/src/utils/axios.jsfrontend/src/utils/myPageMenu.jsfrontend/src/utils/myPageMenuMock.jsfrontend/src/utils/userApi.js
💤 Files with no reviewable changes (2)
- frontend/src/components/mypage/MyPageMenu.jsx
- frontend/src/pages/Mypage.jsx
There was a problem hiding this comment.
Actionable comments posted: 3
♻️ Duplicate comments (2)
frontend/src/components/mypage/EditProfileModal.jsx (1)
130-138:⚠️ Potential issue | 🟠 Major
aria-labelledby가 끊겨 있어서 모달 제목이 전달되지 않습니다.Line 134는
edit-profile-modal-title를 참조하지만, Line 138의<h1>에 해당id가 없습니다. 현재 상태에선 스크린리더가 이 dialog의 accessible name을 읽지 못합니다.수정 예시
<div className={styles.modal} role="dialog" aria-modal="true" aria-labelledby="edit-profile-modal-title" > <div className={styles.modalHeaderColumn}> <div className={styles.modalHeader}> - <h1>{getHeaderTitle()}</h1> + <h1 id="edit-profile-modal-title">{getHeaderTitle()}</h1> </div> </div>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/src/components/mypage/EditProfileModal.jsx` around lines 130 - 138, The modal's aria-labelledby points to "edit-profile-modal-title" but the <h1> rendered by getHeaderTitle() has no matching id, so add id="edit-profile-modal-title" to the heading element (the <h1> that displays getHeaderTitle()) in EditProfileModal.jsx so the dialog's accessible name is announced correctly by screen readers; alternatively, update the dialog's aria-labelledby to match an existing element id if you prefer a different target.frontend/src/components/mypage/ActivitySection.jsx (1)
11-27:⚠️ Potential issue | 🟡 Minor로딩/에러 상태를 UI에서 구분해 주세요.
PR 설명대로 이 화면은 응답 지연이 체감될 수 있는데, 현재는 fetch 중에도 실패 시에도 리스트 영역만 그대로 렌더링됩니다. 그래서 빈 내역인지, 아직 로딩 중인지, 요청이 실패한 건지 구분이 안 됩니다.
loading/error상태를 두고 리스트·빈 상태·에러 표시를 분기하는 편이 안전합니다.Also applies to: 51-65
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/src/components/mypage/ActivitySection.jsx` around lines 11 - 27, Add explicit loading and error state handling around the fetchActivityLogs flow: introduce React state variables (e.g., loading and error via useState), set loading = true before calling getActivityLogs(page, size) and set loading = false in finally; on success clear error and call setItems and setTotalPages as now; on catch set error to the caught error (and optionally clear items). Update the ActivitySection render logic to branch on loading (show spinner), error (show error message/retry), non-empty items (render list), and empty items (render empty state). Apply the same pattern to the other similar fetch block referenced (lines with the second fetch call).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@frontend/src/components/mypage/ActivitySection.jsx`:
- Around line 11-31: The fetchActivityLogs calls can race and allow earlier
(slower) responses to overwrite state; update fetchActivityLogs/useEffect to
ensure only the latest request updates state by adding a cancellation or
sequence guard: either create and use an AbortController for each call and abort
the previous controller before starting a new fetch (wiring the
controller.signal into getActivityLogs), or maintain a monotonic requestId
(useRef) that you increment before each call and check when responses arrive,
only calling setItems/setTotalPages if the response's requestId matches the
latest; update getActivityLogs invocation and the useEffect that triggers
fetchActivityLogs(page) to use this mechanism so stale responses can’t update
the component state.
In `@frontend/src/components/mypage/EditProfileModal.jsx`:
- Around line 37-42: The decorative right-arrow images inside the
EditProfileModal.jsx menu buttons are currently using alt=">" which creates
unnecessary screen-reader noise; update both <img> instances (the ones inside
the buttons that call handleMenuSelect and use styles.menuItem) to be treated as
purely decorative by setting alt="" and adding aria-hidden="true" on the <img>
elements so screen readers ignore them while preserving visual UI.
- Around line 56-61: The verify step currently accepts any email from
EmailVerify via onVerified and only sets verifiedEmail without confirming it
belongs to the logged-in account; update the flow so it either (A) performs
ownership validation by comparing the returned email to the current user's email
(e.g., compare verifiedEmail to currentUser.email from props/context inside this
component before enabling the "continue" button or advancing the step) and
reject/mask advancement if they differ, or (B) remove the email verification
step entirely from the password-change flow; additionally consider changing
EmailVerify/onVerified semantics to return an explicit verified flag (not an
arbitrary email) so this component can enforce ownership using verified === true
&& returnedEmail === currentUser.email before calling setVerifiedEmail or
progressing the step.
---
Duplicate comments:
In `@frontend/src/components/mypage/ActivitySection.jsx`:
- Around line 11-27: Add explicit loading and error state handling around the
fetchActivityLogs flow: introduce React state variables (e.g., loading and error
via useState), set loading = true before calling getActivityLogs(page, size) and
set loading = false in finally; on success clear error and call setItems and
setTotalPages as now; on catch set error to the caught error (and optionally
clear items). Update the ActivitySection render logic to branch on loading (show
spinner), error (show error message/retry), non-empty items (render list), and
empty items (render empty state). Apply the same pattern to the other similar
fetch block referenced (lines with the second fetch call).
In `@frontend/src/components/mypage/EditProfileModal.jsx`:
- Around line 130-138: The modal's aria-labelledby points to
"edit-profile-modal-title" but the <h1> rendered by getHeaderTitle() has no
matching id, so add id="edit-profile-modal-title" to the heading element (the
<h1> that displays getHeaderTitle()) in EditProfileModal.jsx so the dialog's
accessible name is announced correctly by screen readers; alternatively, update
the dialog's aria-labelledby to match an existing element id if you prefer a
different target.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 644eb249-f264-42ec-be1a-b6550fb24c71
📒 Files selected for processing (6)
frontend/src/components/mypage/ActivitySection.jsxfrontend/src/components/mypage/ChangeInfoForm.jsxfrontend/src/components/mypage/EditProfileModal.jsxfrontend/src/components/mypage/MyPageMenu.jsxfrontend/src/components/mypage/ProfileCard.jsxfrontend/src/utils/myPageMenuMock.js
💤 Files with no reviewable changes (2)
- frontend/src/utils/myPageMenuMock.js
- frontend/src/components/mypage/MyPageMenu.jsx
🚧 Files skipped from review as they are similar to previous changes (2)
- frontend/src/components/mypage/ProfileCard.jsx
- frontend/src/components/mypage/ChangeInfoForm.jsx
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
frontend/src/components/mypage/MyPageMenu.jsx (1)
63-68:⚠️ Potential issue | 🔴 Critical
dataprop 누락으로 런타임 에러 발생 확인됨
ActivityModal을 호출할 때dataprop이 제공되지 않았으나,ActivityModal.jsx는 여전히data파라미터를 선언하고 사용합니다:const ActivityModal = ({ isOpen, onClose, title, kind, data }) => { ... {kind === 'attendance' && <AttendanceSection items={data.items} />} {kind === 'activity' && <ActivitySection items={data.items} />} {kind === 'points' && <PointsSection items={data.items} />}
kind이 'activity', 'points', 또는 'attendance'일 때data.items접근 시TypeError: Cannot read property 'items' of undefined에러가 발생합니다.주의:
ActivitySection과PointsSection은itemsprop을 받지 않으며 내부에서 데이터를 페칭합니다.ActivityModal을 수정하여 자식 컴포넌트들의 자체 데이터 페칭 방식과 동기화하거나,MyPageMenu에서dataprop을 전달해야 합니다.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/src/components/mypage/MyPageMenu.jsx` around lines 63 - 68, The modal is crashing because ActivityModal expects a data prop but MyPageMenu wasn’t passing it; update the MyPageMenu ActivityModal invocation to include data={selectedItem?.data} (or the correct payload on selectedItem) and in ActivityModal (component) guard any access to data.items (e.g., only read data.items when kind === 'attendance' && data) while not passing items to ActivitySection or PointsSection (since they fetch their own data); reference components: MyPageMenu, ActivityModal, AttendanceSection, ActivitySection, PointsSection, and prop selectedItem to locate the changes.
♻️ Duplicate comments (1)
frontend/src/utils/axios.js (1)
2-6:⚠️ Potential issue | 🟠 Major프로덕션 환경에서 API 호스트 불일치 문제가 여전히 존재합니다.
BASE_URL을 계산해 두고도baseURL을 빈 문자열로 고정하고 있습니다. Line 20의 토큰 재발급 요청은BASE_URL을 사용하는 반면, 일반 API 요청은 상대 경로로 나가므로 프로덕션에서 nginx proxy 설정 없이는 두 흐름이 서로 다른 호스트를 바라보게 됩니다.이전 리뷰에서 수정된 것으로 표시되었으나, 현재 코드에서는 여전히 동일한 패턴이 보입니다. 의도적인 변경인지 확인이 필요합니다.
수정 제안
const BASE_URL = import.meta.env.DEV ? '' : import.meta.env.VITE_API_URL || ''; export const api = axios.create({ - baseURL: '', + baseURL: BASE_URL, withCredentials: true, });,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/src/utils/axios.js` around lines 2 - 6, The axios instance `api` is created with baseURL set to an empty string while `BASE_URL` is computed, causing host mismatches (token refresh at line ~20 uses BASE_URL but other requests do not); update the `axios.create` call to use the `BASE_URL` constant (i.e., set baseURL: BASE_URL) and ensure any token refresh/request helpers (the token reissue call referenced around line 20) also use the same `api` instance or `BASE_URL` so all requests target the same host.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Outside diff comments:
In `@frontend/src/components/mypage/MyPageMenu.jsx`:
- Around line 63-68: The modal is crashing because ActivityModal expects a data
prop but MyPageMenu wasn’t passing it; update the MyPageMenu ActivityModal
invocation to include data={selectedItem?.data} (or the correct payload on
selectedItem) and in ActivityModal (component) guard any access to data.items
(e.g., only read data.items when kind === 'attendance' && data) while not
passing items to ActivitySection or PointsSection (since they fetch their own
data); reference components: MyPageMenu, ActivityModal, AttendanceSection,
ActivitySection, PointsSection, and prop selectedItem to locate the changes.
---
Duplicate comments:
In `@frontend/src/utils/axios.js`:
- Around line 2-6: The axios instance `api` is created with baseURL set to an
empty string while `BASE_URL` is computed, causing host mismatches (token
refresh at line ~20 uses BASE_URL but other requests do not); update the
`axios.create` call to use the `BASE_URL` constant (i.e., set baseURL: BASE_URL)
and ensure any token refresh/request helpers (the token reissue call referenced
around line 20) also use the same `api` instance or `BASE_URL` so all requests
target the same host.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 85c24525-eeec-4329-a81b-42aa31343c72
📒 Files selected for processing (2)
frontend/src/components/mypage/MyPageMenu.jsxfrontend/src/utils/axios.js
There was a problem hiding this comment.
🧹 Nitpick comments (1)
frontend/src/components/mypage/ActivityModal.jsx (1)
21-40: 접근성 향상을 위해 포커스 트래핑 추가를 권장합니다.현재
role="dialog",aria-modal="true"등 기본적인 접근성 속성은 잘 구현되어 있습니다. 다만, 완전한 모달 접근성을 위해 다음 사항을 고려해 주세요:
- 모달이 열릴 때 포커스를 모달 내부 첫 번째 요소로 이동
- Tab 키로 모달 외부로 포커스가 나가지 않도록 포커스 트래핑
- 모달이 닫힐 때 원래 트리거 요소로 포커스 복귀
♻️ 포커스 트래핑을 위한 useRef 활용 예시
+import { useEffect, useRef } from 'react'; -import { useEffect } from 'react'; import styles from './ActivityModal.module.css'; // ... const ActivityModal = ({ isOpen, onClose, title, kind }) => { + const modalRef = useRef(null); + useEffect(() => { if (!isOpen) return; + + // 모달이 열리면 포커스 이동 + modalRef.current?.focus(); const onKeyDown = (e) => { if (e.key === 'Escape') onClose(); }; // ... }, [isOpen, onClose]); // ... return ( <div className={styles.modalOverlay} /* ... */> - <div className={styles.modalContent} onClick={(e) => e.stopPropagation()}> + <div + ref={modalRef} + tabIndex={-1} + className={styles.modalContent} + onClick={(e) => e.stopPropagation()} + >🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/src/components/mypage/ActivityModal.jsx` around lines 21 - 40, Add focus trapping to the ActivityModal component: store the previously focused element in a ref when the modal mounts, move focus into the modal (e.g., to the first focusable child inside the element referenced by modalContentRef) in useEffect, and restore focus to the saved element when onClose is called or the component unmounts; add a keydown handler on the modal (mounted on the element referenced by modalContentRef or modalOverlay) that intercepts Tab and Shift+Tab to cycle focus among focusable elements inside the modal so focus cannot escape, and ensure the close button (closeButton) still triggers onClose and focus restoration.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@frontend/src/components/mypage/ActivityModal.jsx`:
- Around line 21-40: Add focus trapping to the ActivityModal component: store
the previously focused element in a ref when the modal mounts, move focus into
the modal (e.g., to the first focusable child inside the element referenced by
modalContentRef) in useEffect, and restore focus to the saved element when
onClose is called or the component unmounts; add a keydown handler on the modal
(mounted on the element referenced by modalContentRef or modalOverlay) that
intercepts Tab and Shift+Tab to cycle focus among focusable elements inside the
modal so focus cannot escape, and ensure the close button (closeButton) still
triggers onClose and focus restoration.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: ee9c911c-8319-48d2-a4fb-ad20ad37a590
📒 Files selected for processing (1)
frontend/src/components/mypage/ActivityModal.jsx
1) 작업한 이슈번호
#255 #281
2) 변경 요약 (What & Why)
+출석관리자 페이지 오류 수정
3) 스크린샷/동영상 (UI 변경 시)
4) 상세 변경사항 (전부 다)
/api/user/logs/attendance) 연결totalPages)을 기반으로 페이지 번호 버튼 생성size) 설정하여 불필요한 데이터 요청 최소화/api/user/detailsAPI 연결하여 사용자 정보 수정 가능하도록 구현5) 참고사항
활동 및 포인트 내역 조회시 로딩하는데 시간이 걸림
Summary by CodeRabbit
릴리스 노트
새로운 기능
개선